#pragma once
#include "sublistener.h"
#include <thread>
#include <functional>
#include <optional>
template <typename msg_init_type, typename msg_type> class DDSSubscriber {
public:
  // msg_type = class type of msg

  DDSSubscriber(msg_init_type, msg_type &msg, std::string topic_name,
                eprosima::fastdds::dds::DomainParticipant *participant)
      : subscriber_(nullptr), topic_(nullptr), reader_(nullptr),
        type_(new msg_init_type) {
    
    mMsg_ =  std::ref(msg);

    // Set topic name
    topic_name_ = topic_name;

    // Set pointer to domain participant
    participant_ = participant;

    // Create sublistener object
    listener = std::make_unique<SubListener<msg_type>>(&msg);

    init();
  }

  DDSSubscriber(): subscriber_(nullptr), topic_(nullptr), reader_(nullptr),
        type_(new msg_init_type){

        } 


  virtual ~DDSSubscriber();

  bool init();
  bool init(msg_type &msg, std::string topic_name,
                eprosima::fastdds::dds::DomainParticipant *participant){
                  mMsg_ = std::ref(msg) ;

                  topic_name_ = topic_name;

                  // Set pointer to domain participant
                  participant_ = participant;

                  // Create sublistener object
                  listener = std::make_unique<SubListener<msg_type>>(&msg);

                  return init();
                }

  void run();

  // Custom Variables
  std::string topic_name_{};

  // // Buffer to hold incoming data
  // msg_type msg{};
  void setMsgCallback(std::function<void (msg_type msg)> callback)
   {
    mDoMsg_ = callback;
     MsgThread= std::thread(std::bind(&DDSSubscriber::subMagRun, this));

  }
  void subMagRun()
  {
     //msg_type h264Stream{};
     for (;;) {
       this->listener->wait_for_data();
        //std::cout <<"id2:" << h264Stream2.id() << "---"<<h264Stream2.name()<<std::endl;
       mDoMsg_(mMsg_.value());
     }
  }


public:
  // Pointer to listerner object (contains callbacks)
  std::unique_ptr<SubListener<msg_type>> listener;

private:
  eprosima::fastdds::dds::DomainParticipant *participant_;
  eprosima::fastdds::dds::Subscriber *subscriber_;
  eprosima::fastdds::dds::Topic *topic_;
  eprosima::fastdds::dds::DataReader *reader_;
  eprosima::fastdds::dds::TypeSupport type_;
  std::function<void(msg_type msg)> mDoMsg_;
  std::optional<std::reference_wrapper<msg_type>> mMsg_;
  std::thread MsgThread;
};

#include "default_subscriber.cpp"